#ifndef __CLDATA_H
#define __CLDATA_H 1

#include <boost/mpl/list_c.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/count_if.hpp>
//#include <feel/feelcore/feel.hpp>
#include <feel/feelvf/vf.hpp>

#include <research/life-workspace/Fluid-Structure/cltype.hpp>

namespace Feel
{





#define DIRICHLET_TYPE_NAME2(i)                                     \
    BOOST_PP_TUPLE_ELEM(2, 0, BOOST_PP_ARRAY_ELEM(i,MARKER_LIST)) \
    /**/
#define DIRICHLET_TYPE_STR(i)                                       \
    BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_ARRAY_ELEM(i,MARKER_LIST)) \


    /////////////////////////////////////////////////////////////////////////

#define CL_INSTANTIATES_FOR_COMP(r, state)                              \
    BOOST_PP_NOT_EQUAL( BOOST_PP_TUPLE_ELEM(2, 0, state),               \
                        BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(2, 1, state))  \
                        )                                               \
    /**/
    /*_________________________________________________*/
    /*                                                 */
    /**/
#define CL_INSTANTIATES_FOR_INCR(r, state)              \
    ( BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(2, 0, state)),   \
      BOOST_PP_TUPLE_ELEM(2, 1, state) )                \
    /**/
    /*_________________________________________________*/
    /*                                                 */
    /**/
#define CL_INSTANTIATES_FOR(r,state)                                    \
    DIRICHLET_TYPE_NAME2(BOOST_PP_TUPLE_ELEM(2,0,state)) BOOST_PP_COMMA() \
    /**/
    /*_________________________________________________*/
    /*                                                 */
    /**/
#define CL_MARKER_FOR(r,state)                                          \
    DIRICHLET_TYPE_STR(BOOST_PP_TUPLE_ELEM(2,0,state))  BOOST_PP_COMMA() \
    /*_________________________________________________*/
    /*                                                 */
    /**/



    namespace cl {
        enum cl_markerName_enum
            {
                BOOST_PP_FOR( (0, BOOST_PP_SUB(BOOST_PP_ARRAY_SIZE(MARKER_LIST), 2) ),
                              CL_INSTANTIATES_FOR_COMP,
                              CL_INSTANTIATES_FOR_INCR,
                              CL_INSTANTIATES_FOR )
                /**/
                DIRICHLET_TYPE_NAME2(BOOST_PP_SUB(BOOST_PP_ARRAY_SIZE(MARKER_LIST), 1))
                /**/
            };

#if 0
        enum cl_type_enum
            {
                dirichlet_scal=0,
                dirichlet_vec=1,
                paroi_mobile=2,
                neumann_scal=3
            };
        /*
        //0 scal, 1 vect, 2 mat
        static const int * cl_type_expr[]=
            {
                1,1,0,0
            };
        */
        static const char * cl_type_string[] =
            {
                "dirichlet_scal",
                "dirichlet_vect",
                "paroi_mobile",
                "neumann_scal"
            };
#endif
        static const char * cl_marker_string[] =
            {
                /**/
                BOOST_PP_FOR( (0, BOOST_PP_SUB(BOOST_PP_ARRAY_SIZE(MARKER_LIST), 2) ),
                              CL_INSTANTIATES_FOR_COMP,
                              CL_INSTANTIATES_FOR_INCR,
                              CL_MARKER_FOR )
                /**/
                DIRICHLET_TYPE_STR(BOOST_PP_SUB(BOOST_PP_ARRAY_SIZE(MARKER_LIST), 1))
                /**/
            };

    } // end namespace clType

    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    //Macros usefull for construct clbase class

    // search the global number with the two parameters template
#define CL_NUM_SEARCH(n1,n2)                                            \
    mpl::if_<boost::is_same<boost::tuple<mpl::int_<T0::nType>,mpl::int_<T0::nName> >, \
                            boost::tuple<mpl::int_<n1>,mpl::int_<n2> > >, \
             mpl::int_<0>,                                              \
             typename mpl::if_<boost::is_same<boost::tuple<mpl::int_<T1::nType>,mpl::int_<T1::nName> >, \
                                              boost::tuple<mpl::int_<n1>,mpl::int_<n2> > >, \
                               mpl::int_<1>,                            \
                               typename mpl::if_<boost::is_same<boost::tuple<mpl::int_<T2::nType>,mpl::int_<T2::nName> >, \
                                                                boost::tuple<mpl::int_<n1>,mpl::int_<n2> > >, \
                                                 mpl::int_<2>,          \
                                                 mpl::int_<3> >::type >::type >::type::value \
    /**/

    // get global number with a type and local number
#define CL_LOCAL_TO_GLOBAL(T,numLoc,cldat_ind)                          \
    mpl::fold< cldat_ind,                                               \
               ing<0,0,0>,                                              \
               mpl::if_< mpl::equal_to<  mpl::_2 ,mpl::int_<T> >,       \
                         ingNext<mpl::_1,mpl::bool_<true> ,mpl::int_<numLoc> >, \
                         ingNext<mpl::_1,mpl::bool_<false>,mpl::int_<numLoc> > > \
               >::type::leNum                                           \
    /**/

    // usefull for operator +
#define op_plus_type_dataBase(OOO)                                      \
    typename mpl::if_<boost::is_same<T1,cldataNull>,                    \
                      CLdataBase<T0,                                    \
                                 typename OOO::cldata0_type,            \
                                 typename OOO::cldata1_type ,           \
                                 typename OOO::cldata2_type,            \
                                 typename OOO::cldata3_type >,          \
                      typename mpl::if_<boost::is_same<T2,cldataNull>,  \
                                        CLdataBase<T0, T1,              \
                                                   typename OOO::cldata0_type, \
                                                   typename OOO::cldata1_type, \
                                                   typename OOO::cldata2_type>, \
                                        typename mpl::if_<boost::is_same<T3,cldataNull>, \
                                                          CLdataBase<T0,T1,T2, \
                                                                     typename OOO::cldata0_type, \
                                                                     typename OOO::cldata1_type>, \
                                                          CLdataBase<T0,T1,T2,T3, \
                                                                     typename OOO::cldata0_type> \
                                                          >::type>::type>::type \
    /**/

#define op_plus_type_tuple                                              \
    mpl::int_< mpl::if_<boost::is_same<T1,cldataNull>,                  \
                        mpl::int_<0> ,                                  \
                        typename mpl::if_<boost::is_same<T2,cldataNull>, \
                                          mpl::int_<1>,                 \
                                          typename mpl::if_<boost::is_same<T3,cldataNull>, \
                                                            mpl::int_<2>, \
                                                            mpl::int_<3>/*typename mpl::if_<boost::is_same<T4,cldataNull>, \
                                                                          mpl::int_<3>, \
                                                                          mpl::int_<4> >::type*/ >::type>::type>::type::value \
               >()                                                      \
    /**/

    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    //Macros user
#define ForEachCL2(CLBASE,NUMEXPR,CLT,EXPR)                             \
    switch (NUMEXPR)                                                    \
        {                                                               \
        case 0 : {                                                      \
            /*auto Expression = boost::get<0>(CLBASE.M_cldata).getExpr();*/ \
            /*auto Expression = (CLBASE.M_cldata0)->getExpr();*/        \
            /*auto Expression = CLBASE.template getExpr<0>();*/         \
            auto Expression = CLBASE.template getExprStressType<0,CLT>(); \
            EXPR;                                                       \
            break; }                                                    \
        case 1 : {                                                      \
            auto Expression = CLBASE.template getExprStressType<1,CLT>(); \
            EXPR;                                                       \
            break; }                                                    \
        case 2 : {                                                      \
            auto Expression = CLBASE.template getExprStressType<2,CLT>(); \
            EXPR;                                                       \
            break; }                                                    \
        case 3 : {                                                      \
            auto Expression = CLBASE.template getExprStressType<3,CLT>(); \
            EXPR;                                                       \
            break; }                                                    \
        case 4 : {                                                      \
            auto Expression = CLBASE.template getExprStressType<4,CLT>(); \
            EXPR;                                                       \
            break; }                                                    \
                                                                        \
        }                                                               \
    /**/



#define ForEachCL(CLBASE,CLT,EXPR)                                      \
    for (int i=0;i<CLBASE.template nbCL<CLT>();++i)                     \
        {                                                               \
            switch (i)                                                  \
                {                                                       \
                case 0 :  {                                             \
                    auto PhysicalName = CLBASE.template getMarkerName< CLT,0 >(); \
                    auto numExpr = CLBASE.template localToGlobal<CLT,0>(); \
                    ForEachCL2(CLBASE,numExpr,CLT,EXPR);                \
                    break; }                                            \
                case 1 :  {                                             \
                    auto PhysicalName = CLBASE.template getMarkerName< CLT,1 >(); \
                    auto numExpr = CLBASE.template localToGlobal<CLT,1>(); \
                    ForEachCL2(CLBASE,numExpr,CLT,EXPR);                \
                    break; }                                            \
                case 2 :  {                                             \
                    auto PhysicalName = CLBASE.template getMarkerName< CLT,2 >(); \
                    auto numExpr = CLBASE.template localToGlobal<CLT,2>(); \
                    ForEachCL2(CLBASE,numExpr,CLT,EXPR);                \
                    break;}                                             \
                case 3 :  {                                             \
                    auto PhysicalName = CLBASE.template getMarkerName< CLT,3 >(); \
                    auto numExpr = CLBASE.template localToGlobal<CLT,3>(); \
                    ForEachCL2(CLBASE,numExpr,CLT,EXPR);                \
                    break;}                                             \
                case 4 :  {                                             \
                    auto PhysicalName = CLBASE.template getMarkerName< CLT,4 >(); \
                    auto numExpr = CLBASE.template localToGlobal<CLT,4>(); \
                    ForEachCL2(CLBASE,numExpr,CLT,EXPR);                \
                    break;}                                             \
                }                                                       \
        }                                                               \
    /**/

    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    //usefull for mpl::fold

    template <int nbF,int leN,int lecpt>
    struct ing
    {

        static const int nbFind = nbF;

        static const int leNum = leN;

        static const int cpt = lecpt;

        static const int value = nbFind;

    };


    template<typename C,typename B,typename numLoc>
    struct ingNext
    {
        typedef typename mpl::if_< B ,
                                   ing<C::nbFind+1,
                                       mpl::if_< mpl::equal_to< mpl::int_<C::nbFind>,numLoc >,
                                                 mpl::int_<C::cpt>,
                                                 mpl::int_<C::leNum> >::type::value,
                                       C::cpt+1 >,
                                   ing<C::nbFind,C::leNum,C::cpt+1 > >::type type;

    };



    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
#if 1


    class cldataScal
    {
    public :

        typedef vf::Expr< vf::Cst<double> > expression_type;

        expression_type
        getExpr()
        {
            return vf::cst(0.);
        }

    };

    class cldataVec
    {
    public :

        typedef vf::Expr< vf::One<-1> > expression_type;

        expression_type
        getExpr()
        {
            return vf::one();
        }

    };


    template <int Type>
    class cldataGen
    {
    public:

        static const int scalaire = -1;
        static const int vectoriel = -2;

        static const int dirichletScal=scalaire;
        static const int dirichletVec=vectoriel;
        static const int paroiMobile=vectoriel;
        static const int neumannScal=scalaire;


        static const int nType = mpl::if_< boost::is_same<mpl::int_<cl::dirichlet_scal>,mpl::int_<Type> >,
                                           mpl::int_<dirichletScal>,
                                           typename mpl::if_< boost::is_same<mpl::int_<cl::dirichlet_vec>,mpl::int_<Type> >,
                                                              mpl::int_<dirichletVec>,
                                                              typename mpl::if_< boost::is_same<mpl::int_<cl::paroi_mobile>,mpl::int_<Type> >,
                                                                                 mpl::int_<paroiMobile>,
                                                                                 mpl::int_<neumannScal> >::type>::type>::type::value;
        static const int nName = -1;//nom bidon

        typedef typename mpl::if_< boost::is_same<mpl::int_<nType>,mpl::int_<scalaire> >,
                                   typename cldataScal::expression_type,
                                   typename mpl::if_< boost::is_same<mpl::int_<nType>,mpl::int_<vectoriel> >,
                                                      typename cldataVec::expression_type,
                                                      typename cldataVec::expression_type >::type>::type expression_type;
        //typedef vf::Expr< vf::Cst<double> > expression_type;

        //expression_type
        //getExpr() { return vf::cst(0.); }
        //static
        expression_type
        getExpr()
        {
            //if (nType==0)
            //   return expression_type(vf::Cst(0.));
            //else
            //return expression_type(vf::One<-1>());
            return getExprBid(mpl::int_<nType>());
        }

        typename cldataScal::expression_type
        getExprBid( mpl::int_<0> )
        {
            cldataScal a;
            return a.getExpr();
        }

        typename cldataVec::expression_type
        getExprBid( mpl::int_<1> )
        {
            cldataVec a;
            return a.getExpr();
        }

    };
#endif

    class cldataNull
    {
    public:

        static const int value = 0;

        static const int nType = -1;
        static const int nName = -1;

        typedef vf::Expr< vf::Cst<double> > expression_type;

        expression_type
        getExpr() { return vf::cst(0.); }

    };

    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////
    ////////////////////////////////////////////////////////////////////////////////////////


    template <class T0 /*= cldataNull*/,
              class T1 = cldataNull,
              class T2 = cldataNull,
              class T3 = cldataNull,
              class T4 = cldataNull >
    class CLdataBase :   public mpl::if_<boost::is_same<T1,cldataNull>,
                                         boost::fusion::vector<T0>,
                                         typename mpl::if_<boost::is_same<T2,cldataNull>,
                                                           boost::fusion::vector<T0,T1>,
                                                           typename mpl::if_<boost::is_same<T3,cldataNull>,
                                                                             boost::fusion::vector<T0,T1,T2>,
                                                                             typename mpl::if_<boost::is_same<T4,cldataNull>,
                                                                                               boost::fusion::vector<T0,T1,T2,T3>,
                                                                                               boost::fusion::vector<T0,T1,T2,T3,T4> >::type>::type>::type>::type

    {
    public :

        typedef CLdataBase<T0,T1,T2,T3,T4> self_type;

        typedef boost::fusion::vector<T0,T1,T2,T3,T4> super_type;


        typedef T0 cldata0_type;
        typedef T1 cldata1_type;
        typedef T2 cldata2_type;
        typedef T3 cldata3_type;
        typedef T4 cldata4_type;

        typedef typename mpl::if_<boost::is_same<T1,cldataNull>,
                                  boost::fusion::vector<  mpl::int_<T0::nType> >,
                                  typename mpl::if_<boost::is_same<T2,cldataNull>,
                                                    boost::fusion::vector< mpl::int_<T0::nType>,
                                                                           mpl::int_<T1::nType> > ,
                                                    typename mpl::if_<boost::is_same<T3,cldataNull>,
                                                                      boost::fusion::vector<  mpl::int_<T0::nType> ,
                                                                                              mpl::int_<T1::nType> ,
                                                                                              mpl::int_<T2::nType>  >,
                                                                      typename mpl::if_<boost::is_same<T4,cldataNull>,
                                                                                        boost::fusion::vector<  mpl::int_<T0::nType>,
                                                                                                                mpl::int_<T1::nType> ,
                                                                                                                mpl::int_<T2::nType> ,
                                                                                                                mpl::int_<T3::nType> >,
                                                                                        boost::fusion::vector<  mpl::int_<T0::nType>,
                                                                                                                mpl::int_<T1::nType>,
                                                                                                                mpl::int_<T2::nType>,
                                                                                                                mpl::int_<T3::nType>,
                                                                                                                mpl::int_<T4::nType> >
        >::type>::type>::type>::type cldata_indices_type;

    static const int nbData =
        mpl::if_<boost::is_same<T1,cldataNull>,
                 mpl::int_<1>,
                 typename mpl::if_<boost::is_same<T2,cldataNull>,
                                   mpl::int_<2>,
                                   typename mpl::if_<boost::is_same<T3,cldataNull>,
                                                     mpl::int_<3>,
                                                     typename mpl::if_<boost::is_same<T3,cldataNull>,
                                                                       mpl::int_<4>,
                                                                       mpl::int_<5>  >::type>::type>::type>::type::value;

        ////////////////////////////////////////////////////////////////////////////////////////
        //constructors

        CLdataBase(boost::shared_ptr<T0> const & dat0,
                   boost::shared_ptr<T1> const & dat1 = boost::shared_ptr<cldataNull>(new cldataNull()),
                   boost::shared_ptr<T2> const & dat2 = boost::shared_ptr<cldataNull>(new cldataNull()),
                   boost::shared_ptr<T3> const & dat3 = boost::shared_ptr<cldataNull>(new cldataNull()),
                   boost::shared_ptr<T4> const & dat4 = boost::shared_ptr<cldataNull>(new cldataNull()) )
            :
            M_cldata0(dat0),
            M_cldata1(dat1),
            M_cldata2(dat2),
            M_cldata3(dat3),
            M_cldata4(dat4)
        {}

        CLdataBase(CLdataBase const & M)
            :
            M_cldata0(M.M_cldata0),
            M_cldata1(M.M_cldata1),
            M_cldata2(M.M_cldata2),
            M_cldata3(M.M_cldata3),
            M_cldata4(M.M_cldata4)
        {}


        ////////////////////////////////////////////////////////////////////////////////////////


        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////
        // type access

        template<int N>
        struct Basis
        {
            typedef typename mpl::at_c<super_type,N>::type type;

            static const int nType = type::nType;

            static const int nName = type::nName;
        };

        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////
        // objects access

        boost::shared_ptr<cldataScal>
        getData(mpl::int_<-1>) const  { return boost::shared_ptr<cldataScal>(new cldataScal() ); }

        boost::shared_ptr<cldataVec>
        getData(mpl::int_<-2>) const  { return boost::shared_ptr<cldataVec>(new cldataVec() ); }


        boost::shared_ptr<T0>
        getData(mpl::int_<0> a) const  { return M_cldata0; }

        boost::shared_ptr<T1>
        getData(mpl::int_<1> a) const { return M_cldata1; }

        boost::shared_ptr<T2>
        getData(mpl::int_<2> a) const { return M_cldata2; }

        boost::shared_ptr<T3>
        getData(mpl::int_<3> a) const { return M_cldata3; }

        boost::shared_ptr<T4>
        getData(mpl::int_<4> a) const { return M_cldata4; }

        template<int N>
        boost::shared_ptr<typename Basis<N>::type>
        getData() const
        {
            return getData(mpl::int_<N>());
        }

        template <int numGlob>
        typename Basis< numGlob >::type::expression_type
        getExpr()
        {
            return getData( mpl::int_< numGlob >() )->getExpr();
        }

        template <int c1,int c2>
        typename Basis< CL_NUM_SEARCH(c1,c2) >::type::expression_type
        getExpr()
        {
            return getData( mpl::int_< CL_NUM_SEARCH(c1,c2) >() )->getExpr();
        }
#if 1

        //template<int numGlob>

        template <int numGlob,int Type>
        typename mpl::if_< boost::is_same< mpl::int_< Basis< numGlob >::nType >,
                                           mpl::int_<Type> >,
                           typename Basis< numGlob >::type::expression_type,
                           typename cldataGen<Type>::expression_type >::type
        getExprStressType()
        {
            //return getData( mpl::int_< numGlob >() )->getExpr();

            return getData( mpl::int_< mpl::if_< boost::is_same< mpl::int_< Basis< numGlob >::nType >,
                                                                 mpl::int_<Type> >,
                                                 mpl::int_< numGlob >,
                                                 mpl::int_<cldataGen<Type>::nType > >::type::value >() )->getExpr();
}
        //cl_type_expr
#endif

        template <int Type,int numLoc>
        std::string
        getMarkerName()
        {
            return this->getData(mpl::int_<CL_LOCAL_TO_GLOBAL(Type,numLoc,cldata_indices_type)>())->getMarkerName();
        }

        ////////////////////////////////////////////////////////////////////////////////////////


        template< int Type,int numLoc>
        int
        localToGlobal()
        {
            return CL_LOCAL_TO_GLOBAL(Type,numLoc,cldata_indices_type);
        }


        template <int T>
        int
        nbCL()
        {
            return mpl::count_if< cldata_indices_type,
                                  boost::is_same< _ , mpl::int_<T> > >::type::value;
        }

        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////
        // operator+


        template<typename H>
        op_plus_type_dataBase(H)
        operator+( H const & dat)
        {
            return this->opPlus(op_plus_type_tuple,dat);
        }

        //////////////////////////////////////////////////////////////////////////////
        // operator + functions

        template<typename H>
        op_plus_type_dataBase(H)
        opPlus(mpl::int_<0>,H const & opdat)
        {
            return op_plus_type_dataBase(H) (this->getData<0>(),
                                             opdat.getData<0>(),
                                             opdat.getData<1>(),
                                             opdat.getData<2>(),
                                             opdat.getData<3>());
        }

        template<typename H>
        op_plus_type_dataBase(H)
        opPlus(mpl::int_<1>,H opdat)
        {
            return op_plus_type_dataBase(H) (this->getData<0>(),
                                             this->getData<1>(),
                                             opdat.getData<0>(),
                                             opdat.getData<1>(),
                                             opdat.getData<2>());
        }

        template<typename H>
        op_plus_type_dataBase(H)
        opPlus(mpl::int_<2>,H opdat)
        {
            return op_plus_type_dataBase(H) (this->getData<0>(),
                                             this->getData<1>(),
                                             this->getData<2>(),
                                             opdat.getData<0>(),
                                             opdat.getData<1>() );
        }

        template<typename H>
        op_plus_type_dataBase(H)
        opPlus(mpl::int_<3>,H opdat)
        {
            return op_plus_type_dataBase(H) (this->getData<0>(),
                                             this->getData<1>(),
                                             this->getData<2>(),
                                             this->getData<3>(),
                                             opdat.getData<0>() );
        }

        // fin operator+
        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////

        boost::shared_ptr<T0> M_cldata0;
        boost::shared_ptr<T1> M_cldata1;
        boost::shared_ptr<T2> M_cldata2;
        boost::shared_ptr<T3> M_cldata3;
        boost::shared_ptr<T4> M_cldata4;


    };


        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////////////////


    template <int clType,int clName,typename ExprType>
    class CLdata  : public boost::enable_shared_from_this< CLdata<clType,clName,ExprType> >
    {
    public :

        typedef CLdata<clType,clName,ExprType> self_type;

        static const int nType = clType;
        static const int nName = clName;

        typedef ExprType expression_type;
        typedef boost::shared_ptr<expression_type> expression_ptrtype;

        CLdata()
        {
            M_clString = boost::make_tuple(cl::cl_type_string[clType],cl::cl_marker_string[clName]);
        }

        CLdata(ExprType const & expr)
            :
            M_clExpr(new expression_type(expr))
        {
            M_clString=boost::make_tuple(cl::cl_type_string[clType],cl::cl_marker_string[clName]);
        }

        CLdata(const CLdata & M)
            :
            M_clExpr(M.M_clExpr),
            M_clString(M.M_clString)
        {}

        CLdataBase<self_type>
        convertToBase()
        {
            return CLdataBase<self_type>(this->shared_from_this());
        }

        std::string
        getTypeName() { return boost::get<0>(M_clString); }

        std::string
        getMarkerName() { return boost::get<1>(M_clString); }

        expression_type const &
        getExpr() { return *M_clExpr; }

    private :

        expression_ptrtype M_clExpr;

        boost::tuple<std::string,std::string> M_clString;

    };





#if 0
    template <int cltype,int clname,typename ExprType>
    //boost::shared_ptr<CLdata<cltype,clname,ExprType> >
    boost::shared_ptr< CLdataBase<CLdata<cltype,clname,ExprType> > >
    addCL(ExprType expr)
    {

        typedef CLdata<cltype,clname,ExprType> cl_un_type;
        boost::shared_ptr<CLdata<cltype,clname,ExprType> > clbis(new CLdata<cltype,clname,ExprType>(expr));
        return boost::shared_ptr< CLdataBase< cl_un_type> >(new CLdataBase< cl_un_type>(clbis->shared_from_this()));
    }
#endif



    template <int cltype,int clname,typename ExprType>
    CLdataBase<CLdata<cltype,clname,ExprType> >
    addCL(ExprType expr)
    {

        typedef CLdata<cltype,clname,ExprType> cl_un_type;
        boost::shared_ptr<CLdata<cltype,clname,ExprType> > clbis(new CLdata<cltype,clname,ExprType>(expr));
        auto temp = boost::shared_ptr< CLdataBase< cl_un_type> >(new CLdataBase< cl_un_type>(clbis->shared_from_this()));
        return *temp;
    }


} // end namespace Feel


#endif /* __CLDATA_H */
